package com.niiwoo.civet.account.service.dubbo;/**
 * Created by DELL on 2017/12/5.
 */

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.niiwoo.activity.stage.dto.request.prize.ActivityPrizeStatusReqDTO;
import com.niiwoo.activity.stage.dto.response.prize.UserPrizeResponseDTO;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.BankCard;
import com.niiwoo.civet.account.dao.entity.RollbackRechargeOrder;
import com.niiwoo.civet.account.dao.entity.WithdrawOrder;
import com.niiwoo.civet.account.dto.WithdrawFeeDTO;
import com.niiwoo.civet.account.dto.common.WithdrawOrderDTO;
import com.niiwoo.civet.account.dto.request.*;
import com.niiwoo.civet.account.dto.response.*;
import com.niiwoo.civet.account.enums.*;
import com.niiwoo.civet.account.service.WithdrawDubboService;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.civet.account.service.local.MoneyTotalLocalService;
import com.niiwoo.civet.account.service.local.withdraw.WithdrawOrderService;
import com.niiwoo.civet.account.service.local.withdraw.WithdrawService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerSummaryDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.trade.service.myloan.MyLoanDubboService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.user.dto.request.SimpleOrgInfo;
import com.niiwoo.civet.user.dto.response.UserAccountPropertyResponse;
import com.niiwoo.civet.user.dto.response.ValidUserForbidResponseDTO;
import com.niiwoo.civet.user.dto.response.organization.OrganizationBaseConfigRespDTO;
import com.niiwoo.civet.user.enums.UserForbidTypeEnum;
import com.niiwoo.civet.user.service.OrganizationDubboService;
import com.niiwoo.civet.user.service.UserAccountDubboService;
import com.niiwoo.civet.user.service.UserForbidDubboService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.*;
import com.niiwoo.tripod.lanmao.request.ConfirmWithdrawRequest;
import com.niiwoo.tripod.lanmao.request.QueryTransactionRequest;
import com.niiwoo.tripod.lanmao.response.QueryUserInformationResponse;
import com.niiwoo.tripod.lanmao.response.QueryWithdrawResponse;
import com.niiwoo.tripod.provider.dto.response.PageResponseDTO;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 提现
 *
 * @author xiaoyingping
 * @create 2017-12-05 20:57
 **/
@Slf4j
@Service(version = "1.0.0")
public class WithdrawDubboServiceImpl implements WithdrawDubboService {

    @Autowired
    private WithdrawService withdrawService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private BankCardService bankCardService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private LanMaoSequence lanMaoSequence;
    @Autowired
    private PrivacyMasks privacyMasks;
    @Autowired
    private WithdrawOrderService withdrawOrderService;
    @Autowired
    private LanMaoDirectService lanMaoDirectService;
    @Autowired
    private MoneyTotalLocalService moneyTotalLocalService;


    @Reference(version = "1.0.0")
    private UserForbidDubboService userForbidDubboService;
    @Reference(version = "1.0.0")
    private UserAccountDubboService userAccountDubboService;
    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;
    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;
    @Reference(version = "1.0.0")
    private MyLoanDubboService myLoanDubboService;
    @Reference(version = "1.0.0")
    private ProjectDubboService projectDubboService;
    @Reference(version = "1.0.0")
    private OrganizationDubboService organizationDubboService;


    @Override
    public WithdrawT0CheckResponse checkT0Enable(String userId, UserRoleEnum userRoleEnum, BigDecimal withdrawAmount) {
        //判断用户账户余额是否充足
        AccountBase accountBase = accountService.loadNiiwooAccount(userId, userRoleEnum);
        if (accountBase.getAvailableAmount().compareTo(withdrawAmount) < 0) {
            throw new BizException("ACC10007");
        }

        return withdrawService.checkT0Enable(accountBase,withdrawAmount);
    }

    @Override
    public WithdrawT0CheckResponse checkT0EnableWithOrg(String userId, String pushOrgId, UserRoleEnum userRoleEnum, BigDecimal withdrawAmount) {
        if (StringUtils.isBlank(pushOrgId)) {
            return this.checkT0Enable(userId, userRoleEnum, withdrawAmount);
        }

        AccountBase accountBase = accountService.loadOrgAccount(userId, pushOrgId);
        if (accountBase.getAvailableAmount().compareTo(withdrawAmount) < 0) {
            throw new BizException("ACC10007");
        }

        return withdrawService.checkT0Enable(accountBase,withdrawAmount);
    }

    @Override
    public WithdrawNotifyResponseDTO processSubmitWithdrawNotify(WithdrawNotifyRequestDTO submitWithdrawNotifyRequestDTO) {
        WithdrawNotifyResponseDTO responseDTO = new WithdrawNotifyResponseDTO();
        Long withdrawOrderId = withdrawService.processSubmitWithdrawNotify(submitWithdrawNotifyRequestDTO);
        responseDTO.setWithdrawOrderId(withdrawOrderId);
        return responseDTO;
    }

    @Override
    public void withdrawPaymentSuccess(WithdrawNotifyRequestDTO withdrawNotifyRequestDTO) {
        String requestNo = withdrawNotifyRequestDTO.getRequestNo();
        Long operateUserId = withdrawNotifyRequestDTO.getOperateUserId();
        WithdrawEndTypeEnum endTypeEnum = withdrawNotifyRequestDTO.getEndTypeEnum();

        Assert.hasLength(requestNo, "requestNo不能为空");
        Assert.notNull(operateUserId, "operateUserId不能为空");
        Assert.notNull(endTypeEnum, "endType不能为空");
        withdrawService.withdrawPaymentSuccess(requestNo, operateUserId, endTypeEnum);
    }

    @Override
    public void withdrawPaymentFail(WithdrawNotifyRequestDTO withdrawNotifyRequestDTO) {
        String requestNo = withdrawNotifyRequestDTO.getRequestNo();
        Long operateUserId = withdrawNotifyRequestDTO.getOperateUserId();
        WithdrawEndTypeEnum endTypeEnum = withdrawNotifyRequestDTO.getEndTypeEnum();

        Assert.hasLength(requestNo, "requestNo不能为空");
        Assert.notNull(operateUserId, "operateUserId不能为空");
        Assert.notNull(endTypeEnum, "endType不能为空");
        withdrawService.withdrawPaymentFail(requestNo, operateUserId, endTypeEnum);
    }

    /**
     * 普通用户提现：包括机构推荐的个人借款用户
     * @param requestDTO
     * @return
     */
    @Override
    public WithdrawOrderDTO submitWithdraw(SubmitWithdrawRequestDTO requestDTO) {
        log.info("submitWithdraw请求参数信息："+ JSONObject.toJSONString(requestDTO));
        Assert.notNull(requestDTO, "request object is required");
        Assert.notNull(requestDTO.getAccountId(), "accountId is required");
        Assert.notNull(requestDTO.getAmount(), "amount is required");
        Assert.notNull(requestDTO.getWithdrawType(), "withdrawType is required");

        BigDecimal amount = requestDTO.getAmount(); //理论提现金额
        Boolean isUsePrize = requestDTO.getPrizeId() != null ? true : false;//是否使用红包

        //各种前置判断
        AccountBase accountBase = accountService.loadAccountById(requestDTO.getAccountId());
        String userId = accountBase.getUserId();
        if (AccountActiveEnum.UNACTIVATED.getValue().equals(accountBase.getImportUserActiva())) {
            throw new BizException("ACC10003");//账户未激活
        }
        if (accountBase.getAvailableAmount().compareTo(requestDTO.getAmount()) < 0) {
            throw new BizException("ACC10007");//账户余额不足
        }
        if(amount.compareTo(new BigDecimal("100")) < 0){
            throw new BizException("ACC10040");//单笔提现最低不得小于100元
        }
        ValidUserForbidResponseDTO validUserForbid = userForbidDubboService.queryValidUserForbidInfo(userId, UserForbidTypeEnum.WITHDRAW);
        if (validUserForbid != null) {
            throw new BizException("ACC10027",validUserForbid.getForbidDesc());//行为被禁止
        }
        if(StringUtils.equals(accountBase.getOrgId(), OrgConstant.NIIWOO_ORG_ID)){
            List<ProjectBorrowerSummaryDTO> overdueList = myLoanDubboService.queryMyLoanOverdue(userId);
            if (!CollectionUtils.isEmpty(overdueList)) {
                //排除考拉理财等渠道的项目
                List<ProjectDTO> projectDTOList = overdueList.stream().map(e -> projectDubboService.selectProjectById(e.getProjectId()))
                        .filter(projectDTO -> !ChannelCodeEnum.KAOLA.getChanelCode().equals(projectDTO.getChannelCode()))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(projectDTOList)) {
                    throw new BizException("ACC10037");//有逾期待还借款
                }
            }
        }

        //查询相关配置
        List<TradeConfigEnum> tradeConfigEnumList = new ArrayList<>();
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAWFEE);//正常提现手续费率
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAW_FEE_IN_ACTIVITY);//正常提现活动期手续费率
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_BEGIN);//正常提现活动开始时间
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_END);//正常提现活动截止时间
        tradeConfigEnumList.add(TradeConfigEnum.FASTWITHDRAWFEE);//快速提现手续费率
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_FEE_IN_ACTIVITY);//快速提现活动期手续费率
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_BEGIN);//快速提现活动开始时间
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_END);//快速提现活动截止时间
        tradeConfigEnumList.add(TradeConfigEnum.SINGLEWITHDRAWMAXAMOUNT);//单次提现最高收取多少
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAWMAXAMOUNT);//单笔提现最大交易限额
        tradeConfigEnumList.add(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN);//懒猫页面过期时间

        Map<String, String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(tradeConfigEnumList);
        String expireMinStr = tradeConfigMap.get(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN.getConfigKey());
        Integer expireMin = StringUtils.isEmpty(expireMinStr) ? 5 : Integer.valueOf(expireMinStr);

        //判断单笔提现金额是否超限
        String maxWithdrawAmountStr = tradeConfigMap.get(TradeConfigEnum.WITHDRAWMAXAMOUNT.getConfigKey());
        BigDecimal maxWithdrawAmount = StringUtils.isEmpty(maxWithdrawAmountStr) ? BigDecimal.ZERO : new BigDecimal(maxWithdrawAmountStr);
        if (maxWithdrawAmount.compareTo(BigDecimal.ZERO) != 0) {
            if (maxWithdrawAmount.compareTo(amount) < 0) {
                throw new BizException("ACC10029");//单笔提现金额超限
            }
        }


        /**==========================获取提现手续费率和手续费封顶值 Start===========================*/
        Byte userType = null; //1：提现人、2：机构、3：你我金融
        BigDecimal withdrawFeeRate = null;//提现费率
        BigDecimal maxWithdrawFee = null;//提现费用封顶值
        if(!OrgConstant.NIIWOO_ORG_ID.equals(accountBase.getOrgId()) && !accountBase.getOrgId().equals(accountBase.getUserId())) {
            /**==获取账户所属orgId为机构并且非企业借款人的手续费率配置==*/
            OrganizationBaseConfigRespDTO organizationBaseConfigRespDTO = organizationDubboService.selectOrganizationBaseConfigByOrgId(accountBase.getOrgId());
            if(Objects.isNull(organizationBaseConfigRespDTO)){
                throw new BizException("ACC10028");
            }

            userType = organizationBaseConfigRespDTO.getWithdrawType();
            maxWithdrawFee = organizationBaseConfigRespDTO.getWithdrawMaxFee();
            if (requestDTO.getWithdrawType() == WithdrawTypeEnum.NORMAL) {
                withdrawFeeRate = organizationBaseConfigRespDTO.getWithdrawRateT1();
            } else {
                withdrawFeeRate = organizationBaseConfigRespDTO.getWithdrawRateT0();
            }
        } else {
            userType = 1;

            /**==获取账户所属orgId为"你我金融"的手续费率配置==*/
            DateTimeFormatter dft = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
            String withdrawFeeRateStr = "";
            if (requestDTO.getWithdrawType() == WithdrawTypeEnum.NORMAL) {
                /*****正常提现****/
                //手续费默认为原价
                withdrawFeeRateStr = tradeConfigMap.get(TradeConfigEnum.WITHDRAWFEE.getConfigKey());
                if(OrgConstant.NIIWOO_ORG_ID.equals(accountBase.getOrgId())){
                    //判断正常提现是否有优惠活动(普通账户)
                    String normalWithdrawFeeActivityTimeBeginStr = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_BEGIN.getConfigKey());
                    String normalWithdrawFeeActivityTimeEndStr = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_END.getConfigKey());
                    if(StringUtils.isNotEmpty(normalWithdrawFeeActivityTimeBeginStr) && StringUtils.isNotEmpty(normalWithdrawFeeActivityTimeEndStr)){
                        if(DateTime.parse(normalWithdrawFeeActivityTimeBeginStr, dft).isBeforeNow()  &&  DateTime.parse(normalWithdrawFeeActivityTimeEndStr, dft).isAfterNow()){
                            //手续费设置为活动价
                            withdrawFeeRateStr = tradeConfigMap.get(TradeConfigEnum.WITHDRAW_FEE_IN_ACTIVITY.getConfigKey());
                        }
                    }
                }
            } else {
                /*****快速提现****/
                //手续费默认为原价
                withdrawFeeRateStr = tradeConfigMap.get(TradeConfigEnum.FASTWITHDRAWFEE.getConfigKey());
                //判断正常提现是否有优惠活动
                String fastWithdrawFeeActivityTimeBeginStr = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_BEGIN.getConfigKey());
                String fastWithdrawFeeActivityTimeEndStr = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_END.getConfigKey());
                if(StringUtils.isNotEmpty(fastWithdrawFeeActivityTimeBeginStr) && StringUtils.isNotEmpty(fastWithdrawFeeActivityTimeEndStr)){
                    if(DateTime.parse(fastWithdrawFeeActivityTimeBeginStr, dft).isBeforeNow()  &&  DateTime.parse(fastWithdrawFeeActivityTimeEndStr, dft).isAfterNow()){
                        //活动价
                        withdrawFeeRateStr = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_FEE_IN_ACTIVITY.getConfigKey());
                    }
                }
            }

            if (StringUtils.isEmpty(withdrawFeeRateStr)) {
                throw new BizException("ACC10028");//未配置提现费率
            }
            withdrawFeeRate = new BigDecimal(withdrawFeeRateStr);
            String maxWithdrawFeeStr = tradeConfigMap.get(TradeConfigEnum.SINGLEWITHDRAWMAXAMOUNT.getConfigKey());
            maxWithdrawFee = StringUtils.isEmpty(maxWithdrawFeeStr) ? BigDecimal.ZERO : new BigDecimal(maxWithdrawFeeStr);
        }
        /**==========================获取提现手续费率和手续费封顶值 End===========================*/

        /****==========================计算应收和实收手续费 Start**==========================*/
        WithdrawFeeDTO feeDTO = withdrawService.caculateFee(userType,amount,withdrawFeeRate,maxWithdrawFee);
        BigDecimal fee = feeDTO.getFee();//应收提现手续费
        BigDecimal realFee = feeDTO.getWithdrawRealFee();//实收提现手续费

        Long prizeId = null;
        if (isUsePrize && realFee.compareTo(BigDecimal.ZERO) > 0) {
            //实际手续费不为0且有使用红包,需要扣除红包额度
            UserPrizeResponseDTO userPrizeResponseDTO = activityPrizeDubboService.getUserPrizeInfo(userId, requestDTO.getPrizeId());
            prizeId = userPrizeResponseDTO.getId();
            BigDecimal prizeAmount = userPrizeResponseDTO.getPrizeValue();//红包金额
            if (prizeAmount.compareTo(fee) >= 0) {
                realFee = BigDecimal.ZERO;//如果红包金额大于等于提现手续费，实际提现手续费为0
            }else{
                realFee = fee.subtract(prizeAmount);//如果红包金额小于提现手续费，实际提现手续费 = 手续费 - 红包金额
            }
        }
        /****==========================计算应收和实收手续费 End**==========================*/

        //计算实际提现金额
        BigDecimal realAmount = amount;
        if (accountBase.getAvailableAmount().compareTo(amount.add(realFee)) < 0) {
            //如果 账户余额<(提现金额+实际手续费) 手续费从实际提现金额中扣除
            realAmount = amount.subtract(realFee);
        }

        //如果用户选择加急提现，进行垫资判断，获取应垫资金额
        WithdrawT0CheckResponse withdrawT0CheckResponse = null;
        BigDecimal advanceAmount = null;//应垫资金额
        if (requestDTO.getWithdrawType() == WithdrawTypeEnum.URGENT) {
            withdrawT0CheckResponse = withdrawService.checkT0Enable(accountBase,realAmount);
            //当前账户有一笔快速提现正在审核中
            if(withdrawT0CheckResponse.getHasFastWithdrawInApprove()){
               throw new BizException("ACC10041");
            }
            //结算繁忙（垫资额度不足）
            if (!withdrawT0CheckResponse.getT0Enable()) {
                throw new BizException("ACC10030");
            }
            advanceAmount = withdrawT0CheckResponse.getAdvanceAmount();
        }

        //查询用户信息
        UserAccountPropertyResponse userInfo = userAccountDubboService.getAccountProperty(userId);
        //查询用户银行卡信息
        BankCard bankCard = bankCardService.loadBankCard(accountBase);
        //初始化提现订单
        Date createTime = new Date();
        Date expireTime = new DateTime(createTime).plusMinutes(expireMin).toDate();
        WithdrawOrder withdrawOrder = new WithdrawOrder();
        withdrawOrder.setId(snowflakeIdWorker.nextId());
        withdrawOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withdrawOrder.setUserId(accountBase.getUserId());
        withdrawOrder.setAccountId(accountBase.getId());
        withdrawOrder.setAccountRole(accountBase.getAccountRole());
        withdrawOrder.setRealName(userInfo.getRealName());
        withdrawOrder.setMobileNo(userInfo.getMobileNo());
        withdrawOrder.setBankCardId(bankCard.getId());
        withdrawOrder.setBankCode(bankCard.getBankCode());
        withdrawOrder.setBusinessType(requestDTO.getWithdrawBusinessType().getValue());
        withdrawOrder.setWithdrawType(requestDTO.getWithdrawType().getValue());
        withdrawOrder.setIsAuto(requestDTO.getWithdrawAutoType().getValue());
        withdrawOrder.setAmount(realAmount.add(realFee));
        withdrawOrder.setRealAmout(realAmount);
        withdrawOrder.setFee(fee);
        withdrawOrder.setRealFee(realFee);
        withdrawOrder.setAdvanceAmount(advanceAmount);
        withdrawOrder.setPrizeId(prizeId);
        withdrawOrder.setStatus(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode());
        withdrawOrder.setCreateTime(createTime);
        withdrawOrder.setExpiredTime(expireTime);
        withdrawOrder.setWithdrawFeeRate(withdrawFeeRate);
        withdrawOrder.setFeePaymentUserType(userType);
        withdrawOrderService.initWithdrawOrder(withdrawOrder);

        //确保提现订单事务提交后使用红包
        BigDecimal prizeDeductedAmount = null; //红包实际抵扣的金额
        ActivityPrizeStatusReqDTO prizeStatusReqDTO = null;
        if (isUsePrize) {
            //红包实际抵扣金额 =  手续费 - 实际提现手续费
            prizeDeductedAmount = fee.subtract(realFee);
            //预使用红包
            prizeStatusReqDTO = new ActivityPrizeStatusReqDTO();
            prizeStatusReqDTO.setOrderNo(withdrawOrder.getId());
            prizeStatusReqDTO.setUserId(userId);
            prizeStatusReqDTO.setPrizeId(requestDTO.getPrizeId());
            prizeStatusReqDTO.setRealUseAmount(prizeDeductedAmount);
            activityPrizeDubboService.setPrizeUsedToOccupied(prizeStatusReqDTO);
        }

        //封装返回对象
        WithdrawOrderDTO withdrawOrderDTO = new WithdrawOrderDTO();
        withdrawOrderDTO.setOrderId(withdrawOrder.getId());
        withdrawOrderDTO.setRequestNo(withdrawOrder.getRequestNo());
        withdrawOrderDTO.setAccountNo(accountBase.getAccountNo());
        withdrawOrderDTO.setExpired(withdrawOrder.getExpiredTime());
        withdrawOrderDTO.setAmount(withdrawOrder.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
        withdrawOrderDTO.setFee(realFee.setScale(2, BigDecimal.ROUND_HALF_UP));
        withdrawOrderDTO.setWithdrawType(WithdrawTypeEnum.enumOf(withdrawOrder.getWithdrawType()));

        log.info("submitWithdraw计算结果："+ JSONObject.toJSONString(withdrawOrderDTO));
        return withdrawOrderDTO;
    }

    @Override
    public void confirmWithdraw(Long withdrawOrderId) {
        Assert.notNull(withdrawOrderId, "withdrawOrderId不能为空");
        withdrawService.confirmWithdraw(withdrawOrderId);
    }

    @Override
    public void cancelWithdraw(Long withdrawOrderId) {
        Assert.notNull(withdrawOrderId, "withdrawOrderId不能为空");
        withdrawService.cancelWithdraw(withdrawOrderId);

    }

    @Override
    public PageResponseDTO<WithdrawOrderResponseDTO> pageWithdrawOrders(WithdrawOrderQueryRequest withdrawOrderQueryRequest) {
        Assert.notNull(withdrawOrderQueryRequest, "withdrawOrderQueryRequest不能为空");
        Assert.notNull(withdrawOrderQueryRequest.getUserId(), "userId不能为空");

        PageInfo<WithdrawOrder> pageInfo = withdrawOrderService.pageWithdrawOrders(withdrawOrderQueryRequest);
        List<WithdrawOrder> withdrawOrderList = pageInfo.getList();
        List<WithdrawOrderResponseDTO> withdrawOrderDTOList = withdrawOrderList.stream().map(e -> {
            WithdrawOrderResponseDTO dto = new WithdrawOrderResponseDTO();
            dto.setId(e.getId());
            dto.setAmount(e.getAmount());
            dto.setRealAmount(e.getRealAmout());
            dto.setAccountRole(e.getAccountRole());
            dto.setStatus(e.getStatus());
            dto.setCreateTime(e.getCreateTime());

            return dto;
        }).collect(Collectors.toList());

        PageResponseDTO<WithdrawOrderResponseDTO> pageResponse = new PageResponseDTO<>();
        pageResponse.setTotalCount(Long.valueOf(pageInfo.getTotal()).intValue());
        pageResponse.setTotalPage(pageInfo.getPages());
        pageResponse.setItems(withdrawOrderDTOList);

        return pageResponse;
    }

    @Override
    public BigDecimal queryUserTotalSuccessAmount(String userId) {
        Assert.hasLength(userId, "userId不能为空");
        QueryMoneyTotalResponseDTO queryMoneyTotalResponseDTO = moneyTotalLocalService.queryMoneyTotal(userId,null);
        return queryMoneyTotalResponseDTO.getWithdrawTotal();
    }

    @Override
    public void backrollRechargeNotify(BackrollRechargeRequestDTO requestDTO) {
        Assert.notNull(requestDTO, "request object is required");
        Assert.notNull(requestDTO.getRollbackAmount(), "rollbackAmount is required");
        Assert.notNull(requestDTO.getRequestNo(), "requestNo is required");
        Assert.notNull(requestDTO.getWithdrawRequestNo(), "withdrawRequestNo is required");
        Assert.notNull(requestDTO.getCompletedTime(), "completedTime is required");

        //提现订单查询
        WithdrawOrder withdrawOrder = withdrawOrderService.loadWithdrawOrderByRequestNo(requestDTO.getWithdrawRequestNo());
        RollbackRechargeOrder rechargeOrder = new RollbackRechargeOrder();
        rechargeOrder.setCreateTime(new Date());
        rechargeOrder.setId(snowflakeIdWorker.nextId());
        rechargeOrder.setWithdrawOrderId(withdrawOrder.getId());
        rechargeOrder.setWithdrawRequestNo(withdrawOrder.getRequestNo());
        rechargeOrder.setUserId(withdrawOrder.getUserId());
        rechargeOrder.setRequestNo(requestDTO.getRequestNo());
        rechargeOrder.setRollbackAmount(requestDTO.getRollbackAmount());
        rechargeOrder.setRollbackFee(requestDTO.getRollbackCommission());
        rechargeOrder.setAccountId(withdrawOrder.getAccountId());
        rechargeOrder.setAccountRole(withdrawOrder.getAccountRole());
        rechargeOrder.setMobileNo(withdrawOrder.getMobileNo());
        rechargeOrder.setRealName(withdrawOrder.getRealName());
        rechargeOrder.setRollbackType(BackRollRechargeTypeEnum.enumOfByCode(requestDTO.getRollbackType()).getValue());
        rechargeOrder.setSuccessTime(requestDTO.getCompletedTime());

        //插入资金回冲订单，不与提现失败动作保持一致性，每次通知都记录
        withdrawService.addBackrollRechargeOrder(rechargeOrder);
        //进行提现失败处理
        withdrawService.withdrawPaymentFail(rechargeOrder.getWithdrawRequestNo(), 0L, WithdrawEndTypeEnum.SYSTEM_AUTO);
    }

    @Override
    public void withdrawPreSubmissionJob() {
        AccountBase account = null;
        CompletableFuture<QueryWithdrawResponse> completableFuture = null;
        QueryTransactionRequest request = null;
        QueryWithdrawResponse response = null;
        QueryWithdrawResponse.WithdrawDetail withdrawDetail = null;

        //查询状态为预提交的不包括最近5分钟的数据
        List<WithdrawOrder> withdrawOrderList = withdrawOrderService.listWithdrawOrdersForPreSubmissionJob();

        if (withdrawOrderList == null || withdrawOrderList.size() == 0) {
            log.info("withdrawPreSubmissionJob-count:0");
            return;
        }
        log.info("withdrawPreSubmissionJob-count：{},info:{}", withdrawOrderList.size(),JSON.toJSONString(withdrawOrderList));
        for (WithdrawOrder withdrawOrder : withdrawOrderList) {
            try {
                //首先查询存管状态
                account = accountService.loadAccountById(withdrawOrder.getAccountId());
                //首先查询存管实时状态
                request = new QueryTransactionRequest();
                request.setPlatformUserNo(account.getAccountNo());
                request.setTransactionType(TradeQueryTypeEnum.WITHDRAW);
                request.setRequestNo(withdrawOrder.getRequestNo());
                completableFuture = lanMaoDirectService.queryWithdraw(request);
                try {
                    log.info("提现补单提现查询请求参数：{}",JSON.toJSONString(request));
                    response = completableFuture.get();
                    log.info("提现补单提现查询响应结果：{}",JSON.toJSONString(response));
                } catch (Exception e) {
                    log.error("withdrawPreSubmissionJob提现订单查询异常：{}", JSON.toJSONString(withdrawOrder), e);
                    continue;
                }
                //超时
                if (LanMaoErrorCodeEnum.QUERY_OBJECT_NOT_EXIST.getCode().equals(response.getErrorCode())) {
                    Date now = new Date();
                    if (withdrawOrder.getExpiredTime().before(now)) {
                        //关闭提现订单
                        withdrawService.closeWithdrawOrder(withdrawOrder.getUserId(), withdrawOrder.getId(),withdrawOrder.getPrizeId());
                    }
                    continue;
                }
                //掉单
                if (response.isSuccess()) {
                    if (response.getRecords() == null || response.getRecords().size() == 0) {
                        continue;
                    }
                    withdrawDetail = response.getRecords().get(0);
                    if (withdrawDetail == null) {
                        continue;
                    }
                    WithdrawNotifyRequestDTO withdrawNotifyRequestDTO = new WithdrawNotifyRequestDTO();
                    withdrawNotifyRequestDTO.setAmount(withdrawDetail.getAmount());
                    withdrawNotifyRequestDTO.setFloatAmount(withdrawDetail.getFloatAmount());
                    withdrawNotifyRequestDTO.setPlatformUserNo(withdrawDetail.getPlatformUserNo());
                    withdrawNotifyRequestDTO.setRequestNo(withdrawOrder.getRequestNo());
                    withdrawNotifyRequestDTO.setOperateUserId(null);
                    //如果是待确认提现，走待确认提现首次回调流程
                    if (withdrawDetail.getStatus() == WithdrawStatusEnum.CONFIRMING) {
                        withdrawService.processSubmitWithdrawNotify(withdrawNotifyRequestDTO);
                    }
                    //如果是平台提现免审核的走的是非待确认提现，可能是已受理或者出款中的状态
                    if ((withdrawDetail.getStatus() == WithdrawStatusEnum.ACCEPT || withdrawDetail.getStatus() == WithdrawStatusEnum.REMITING)
                            && WithdrawBusinessTypeEnum.NIIWOO_PLATFORM_WITHDRAW.getValue().equals(withdrawOrder.getBusinessType())) {
                        withdrawService.processSubmitWithdrawPlateNotify(withdrawNotifyRequestDTO);
                    }
                }
            } catch (Exception e) {
                log.error("withdrawPreSubmissionJob补单异常:{}", JSON.toJSONString(withdrawOrder), e);
            }

        }
    }

    @Override
    public void withdrawSuccessFailureJobT0() {
        //查询所有状态为出款中的数据
        List<WithdrawOrder> withdrawOrderList = withdrawOrderService.listT0WithdrawOrdersForSuccessFailureJob();
        if (withdrawOrderList == null || withdrawOrderList.size() == 0) {
            log.info("withdrawSuccessFailureJobT0-count:0");
            return;
        }
        log.info("withdrawSuccessFailureJobT0-count：{},info:{}", withdrawOrderList.size(),JSON.toJSONString(withdrawOrderList));
        this.withdrawSuccessFailureJobProcess(withdrawOrderList);
    }

    @Override
    public void withdrawSuccessFailureJobT1() {
        //查询所有状态为出款中的数据
        List<WithdrawOrder> withdrawOrderList = withdrawOrderService.listT1WithdrawOrdersForSuccessFailureJob();
        if (withdrawOrderList == null || withdrawOrderList.size() == 0) {
            log.info("withdrawSuccessFailureJobT1-count:0");
            return;
        }
        log.info("withdrawSuccessFailureJobT1-count：{},info:{}", withdrawOrderList.size(),JSON.toJSONString(withdrawOrderList));
        this.withdrawSuccessFailureJobProcess(withdrawOrderList);
    }

    private void withdrawSuccessFailureJobProcess(List<WithdrawOrder> withdrawOrderList){
        AccountBase account = null;
        CompletableFuture<QueryWithdrawResponse> completableFuture = null;
        QueryTransactionRequest request = null;
        QueryWithdrawResponse response = null;
        QueryWithdrawResponse.WithdrawDetail withdrawDetail = null;
        WithdrawEndTypeEnum endTypeEnum = WithdrawEndTypeEnum.TIMING_JOB;
        for (WithdrawOrder withdrawOrder : withdrawOrderList) {
            try {
                //首先查询存管状态
                account = accountService.loadAccountById(withdrawOrder.getAccountId());
                //首先查询存管实时状态
                request = new QueryTransactionRequest();
                request.setPlatformUserNo(account.getAccountNo());
                request.setTransactionType(TradeQueryTypeEnum.WITHDRAW);
                request.setRequestNo(withdrawOrder.getRequestNo());
                completableFuture = lanMaoDirectService.queryWithdraw(request);
                try {
                    log.info("提现补单提现查询请求参数：{}",JSON.toJSONString(request));
                    response = completableFuture.get();
                    log.info("提现补单提现查询响应结果：{}",JSON.toJSONString(response));
                } catch (Exception e) {
                    log.error("withdrawSuccessFailureJob提现订单查询异常：{}", JSON.toJSONString(withdrawOrder), e);
                    continue;
                }
                //掉单
                if (response.isSuccess()) {
                    if (response.getRecords() == null || response.getRecords().size() == 0) {
                        continue;
                    }
                    withdrawDetail = response.getRecords().get(0);
                    if (withdrawDetail == null) {
                        continue;
                    }
                    //如果是待确认提现，走待确认提现首次回调流程
                    if (withdrawDetail.getStatus() == WithdrawStatusEnum.SUCCESS) {
                        withdrawService.withdrawPaymentSuccess(withdrawOrder.getRequestNo(), null, endTypeEnum);
                    }
                    //受理失败，确认为提现失败，因不涉及到资金回冲，可以直接调用提现失败业务流程
                    if (withdrawDetail.getStatus() == WithdrawStatusEnum.ACCEPT_FAIL){
                        log.info("定时任务查询提现受理失败:{}",withdrawOrder.getRequestNo());
                        withdrawService.withdrawPaymentFail(withdrawOrder.getRequestNo(), null, endTypeEnum);
                    }
                    //如果是体现失败
                    if (withdrawDetail.getStatus() == WithdrawStatusEnum.FAIL) {
                        log.info("定时任务查询提现失败:{}",withdrawOrder.getRequestNo());
                        //如果资金回冲状态为成功，才可以走提现失败流程
                        if(withdrawDetail.getBackRollStatus() == BackRollStatusEnum.SUCCESS){
                            withdrawService.withdrawPaymentFail(withdrawOrder.getRequestNo(), null, endTypeEnum);
                        }

                    }
                }
            } catch (Exception e) {
                log.error("withdrawSuccessFailureJob补单异常:{}", JSON.toJSONString(withdrawOrder), e);
            }
        }
    }

    @Override
    public void withdrawConfirmCancelJob() {
        AccountBase account = null;
        CompletableFuture<QueryWithdrawResponse> completableFuture = null;
        QueryTransactionRequest request = null;
        QueryWithdrawResponse response = null;
        QueryWithdrawResponse.WithdrawDetail withdrawDetail = null;
        log.info("withdrawConfirmCancelJob start");
        //查询所有审核通过/或不通过，但提现状态还是待确认的订单
        List<WithdrawOrder> withdrawOrderList = withdrawOrderService.listWithdrawOrdersForConfirmCancelJob();
        if (withdrawOrderList == null || withdrawOrderList.size() == 0) {
            log.info("withdrawConfirmCancelJob-count:0");
            return;
        }
        log.info("withdrawConfirmCancelJob-count：{},info:{}", withdrawOrderList.size(),JSON.toJSONString(withdrawOrderList));
        for (WithdrawOrder withdrawOrder : withdrawOrderList) {
            try {
                //首先查询存管状态
                account = accountService.loadAccountById(withdrawOrder.getAccountId());
                //首先查询存管实时状态
                request = new QueryTransactionRequest();
                request.setPlatformUserNo(account.getAccountNo());
                request.setTransactionType(TradeQueryTypeEnum.WITHDRAW);
                request.setRequestNo(withdrawOrder.getRequestNo());
                completableFuture = lanMaoDirectService.queryWithdraw(request);
                try {
                    log.info("提现补单提现查询请求参数：{}",JSON.toJSONString(request));
                    response = completableFuture.get();
                    log.info("提现补单提现查询响应结果：{}",JSON.toJSONString(response));
                } catch (Exception e) {
                    log.error("withdrawConfirmCancelJob提现订单查询异常：{}", JSON.toJSONString(withdrawOrder), e);
                    continue;
                }

                if (response.isSuccess()) {
                    if (response.getRecords() == null || response.getRecords().size() == 0) {
                        continue;
                    }
                    withdrawDetail = response.getRecords().get(0);
                    if (withdrawDetail == null) {
                        continue;
                    }
                    //如果存管订单状态是待确认。则对虽有非自动提现的订单进行提现确认/取消 补单动作。
                    if (withdrawDetail.getStatus() == WithdrawStatusEnum.CONFIRMING) {
                        if (WithdrawOrderAuditStatusEnum.PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
                            withdrawService.confirmWithdraw(withdrawOrder.getId());
                        }
                        if (WithdrawOrderAuditStatusEnum.NOT_PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
                            withdrawService.cancelWithdraw(withdrawOrder.getId());
                        }
                    }
                    //如果存管已受理，但我方状态还是待确认，修改我方状态为出款中
                    else if(withdrawDetail.getStatus() == WithdrawStatusEnum.ACCEPT
                            || withdrawDetail.getStatus() == WithdrawStatusEnum.REMITING){
                        withdrawOrderService.updateStatus(withdrawOrder.getId(),WithdrawOrderStatusEnum.OUTING,null);
                    }
                    //如果存管受理失败，但我方状态还是待确认，直接调用提现失败分支
                    else if(withdrawDetail.getStatus() == WithdrawStatusEnum.ACCEPT_FAIL
                            || withdrawDetail.getStatus() == WithdrawStatusEnum.FAIL){

                        log.info("提现确认取消定时任务查询提现受理失败:{}",withdrawOrder.getRequestNo());

                        withdrawService.withdrawPaymentFail(withdrawOrder.getRequestNo(), null, WithdrawEndTypeEnum.TIMING_JOB);

                        //对于非自动提现，由于懒猫BUG问题（受理失败一些特殊情况未自动释放冻结金），
                        //调用一次提现取消接口，由于懒猫特殊情况才会发生此问题，仅日志记录请求报文，不生成提现取消订单，不关注响应及异常
                        try{
                            if(WithdrawAutoType.NORMAL.getValue().equals(withdrawOrder.getIsAuto())
                                    && withdrawDetail.getStatus() == WithdrawStatusEnum.ACCEPT_FAIL){
                                ConfirmWithdrawRequest confirmWithdrawRequest = new ConfirmWithdrawRequest();
                                confirmWithdrawRequest.setRequestNo(lanMaoSequence.getRequestNo());
                                confirmWithdrawRequest.setPreTransactionNo(withdrawOrder.getRequestNo());
                                log.info("懒猫BUG提现确认补单流程提现取消请求：{}",JSON.toJSONString(confirmWithdrawRequest));
                                lanMaoDirectService.cancelWithdraw(confirmWithdrawRequest);
                            }
                        }catch(Exception expect){

                        }
                    }
                }
            } catch (Exception e) {
                log.error("withdrawConfirmCancelJob补单异常:{}", JSON.toJSONString(withdrawOrder), e);
            }
        }
        log.info("withdrawConfirmCancelJob end");
    }

    public WithdrawOrderDTO plateFormSubmitWithdraw(SubmitWithdrawRequestDTO requestDTO) {
        Assert.notNull(requestDTO, "request object is required");
        Assert.notNull(requestDTO.getUserId(), "userId is required");
        Assert.notNull(requestDTO.getAccountId(), "accountId is required");
        Assert.notNull(requestDTO.getAmount(), "amount is required");

        BigDecimal amount = requestDTO.getAmount(); //理论提现金额
        BigDecimal realAmount = amount; //实际提现金额
        BigDecimal fee = BigDecimal.ZERO; //理论提现手续费
        BigDecimal realFee = BigDecimal.ZERO;//实际提现手续费

        //查询相关配置
        List<TradeConfigEnum> tradeConfigEnumList = new ArrayList<>();
        tradeConfigEnumList.add(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN);//懒猫页面过期时间
        Map<String, String> configMap = tradeConfigDubboService.selectTradeConfigByEmuns(tradeConfigEnumList);

        String expireMinStr = configMap.get(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN.getConfigKey());

        Integer expireMin = StringUtils.isEmpty(expireMinStr) ? 5 : Integer.parseInt(expireMinStr);

        //账户未开户
        AccountBase accountBase = accountService.loadAccountById(requestDTO.getAccountId());
        //账户未激活
        if (AccountActiveEnum.UNACTIVATED.getValue().equals(accountBase.getImportUserActiva())) {
            throw new BizException("ACC10003");
        }
        //账户余额不足
        if (accountBase.getAvailableAmount().compareTo(requestDTO.getAmount()) < 0) {
            throw new BizException("ACC10007");
        }
        //查询用户银行卡信息
        BankCard bankCard = bankCardService.getSimpleUserBankCard(requestDTO.getUserId());
        if (bankCard == null) {
            throw new BizException("ACC10012");
        }
        //初始化提现订单
        Date createTime = new Date();
        Date expireTime = new DateTime(createTime).plusMinutes(expireMin).toDate();
        WithdrawOrder withdrawOrder = new WithdrawOrder();
        withdrawOrder.setId(snowflakeIdWorker.nextId());
        withdrawOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withdrawOrder.setUserId(accountBase.getUserId());
        withdrawOrder.setAccountId(accountBase.getId());
        withdrawOrder.setAccountRole(accountBase.getAccountRole());
        withdrawOrder.setRealName(bankCard.getRealName());
        withdrawOrder.setMobileNo(bankCard.getMobileNo());
        withdrawOrder.setBankCardId(bankCard.getId());
        withdrawOrder.setBankCode(bankCard.getBankCode());
        withdrawOrder.setBusinessType(requestDTO.getWithdrawBusinessType().getValue());
        withdrawOrder.setWithdrawType(requestDTO.getWithdrawType().getValue());
        withdrawOrder.setIsAuto(requestDTO.getWithdrawAutoType().getValue());
        withdrawOrder.setAmount(amount);
        withdrawOrder.setRealAmout(realAmount);
        withdrawOrder.setFee(fee);
        withdrawOrder.setRealFee(realFee);
        withdrawOrder.setAdvanceAmount(BigDecimal.ZERO);
        withdrawOrder.setPrizeId(null);
        withdrawOrder.setStatus(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode());
        withdrawOrder.setCreateTime(createTime);
        withdrawOrder.setExpiredTime(expireTime);
        withdrawOrderService.initWithdrawOrder(withdrawOrder);

        //封装返回对象
        WithdrawOrderDTO withdrawOrderDTO = new WithdrawOrderDTO();
        withdrawOrderDTO.setOrderId(withdrawOrder.getId());
        withdrawOrderDTO.setRequestNo(withdrawOrder.getRequestNo());
        withdrawOrderDTO.setAccountNo(accountBase.getAccountNo());
        withdrawOrderDTO.setExpired(withdrawOrder.getExpiredTime());
        withdrawOrderDTO.setAmount(realAmount);
        withdrawOrderDTO.setWithdrawType(WithdrawTypeEnum.enumOf(withdrawOrder.getWithdrawType()));

        return withdrawOrderDTO;
    }

    @Override
    public WithdrawNotifyResponseDTO processSubmitWithdrawPlateNotify(WithdrawNotifyRequestDTO withdrawNotifyRequestDTO) {
        WithdrawNotifyResponseDTO responseDTO = new WithdrawNotifyResponseDTO();
        Long withdrawOrderId = withdrawService.processSubmitWithdrawPlateNotify(withdrawNotifyRequestDTO);
        responseDTO.setWithdrawOrderId(withdrawOrderId);
        return responseDTO;
    }

    @Override
    public WithdrawOrderDTO guaranteeSubmitWithdraw(OrgSubmitRequestDTO requestDTO) {
        Assert.notNull(requestDTO, "request object is required");
        Assert.notNull(requestDTO.getUserId(), "userId is required");
        Assert.notNull(requestDTO.getAccountId(), "accountId is required");
        Assert.notNull(requestDTO.getAmount(), "amount is required");


        BigDecimal accountBalance = null;//账户余额
        BigDecimal amount = requestDTO.getAmount(); //理论提现金额
        BigDecimal realAmount = null; //实际提现金额
        BigDecimal fee = null; //理论提现手续费
        BigDecimal realFee = null;//实际提现手续费
        BigDecimal prizeAmount = null;//红包金额

        //查询相关配置
        List<TradeConfigEnum> tradeConfigEnumList = new ArrayList<>();
        tradeConfigEnumList.add(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN);//懒猫页面过期时间
        Map<String, String> configMap = tradeConfigDubboService.selectTradeConfigByEmuns(tradeConfigEnumList);

        String expireMinStr = configMap.get(TradeConfigEnum.LANMAO_PAGE_EXPIRE_MIN.getConfigKey());
        if(StringUtils.isBlank(requestDTO.getWithdrawRate()) ||StringUtils.isBlank(requestDTO.getMaxWithdrawFee())){
            throw new BizException("ACC6001");
        }
        BigDecimal withdrawFeeRateStr=new BigDecimal(requestDTO.getWithdrawRate());
        BigDecimal maxWithdrawFeeStr=new BigDecimal(requestDTO.getMaxWithdrawFee());

        Integer expireMin = StringUtils.isEmpty(expireMinStr) ? 5 : Integer.parseInt(expireMinStr);
        BigDecimal withdrawFeeRate = BigDecimal.ZERO.compareTo(withdrawFeeRateStr) ==0 ? BigDecimal.ZERO : withdrawFeeRateStr;
        BigDecimal maxWithdrawFee = BigDecimal.ZERO.compareTo(maxWithdrawFeeStr)==0 ? BigDecimal.ZERO : maxWithdrawFeeStr;

        //账户未开户
        AccountBase accountBase = accountService.loadAccountById(requestDTO.getAccountId());
        //账户未激活
        if (AccountActiveEnum.UNACTIVATED.getValue().equals(accountBase.getImportUserActiva())) {
            throw new BizException("ACC10003");
        }
        //未配置提现手续费
        if (BigDecimal.ZERO.compareTo(withdrawFeeRateStr) == 0) {
            throw new BizException("ACC10028");
        }
        //账户余额不足
        if (accountBase.getAvailableAmount().compareTo(requestDTO.getAmount()) < 0) {
            throw new BizException("ACC10007");
        }

        //查询用户银行卡信息
        BankCard bankCard = bankCardService.getOrgUserBankCard(requestDTO.getAccountId());
        if (bankCard == null) {
            throw new BizException("ACC10012");
        }
        //单笔提现最低不得小于100元
        if(amount.compareTo(new BigDecimal("100")) < 0){
            throw new BizException("ACC10040");
        }
        if(amount.compareTo(new BigDecimal("5000000")) > 0){
            throw new BizException("ACC6002");
        }

        WithdrawFeeDTO feeDTO =  withdrawService.caculateFee(requestDTO.getFeePaymentUserType(),requestDTO.getAmount(),withdrawFeeRate,maxWithdrawFee);
        fee = feeDTO.getFee();

        //实际提现手续费默认与理论提现手续费一致。
        realFee = feeDTO.getWithdrawRealFee();

        //账户余额
        accountBalance = accountBase.getAvailableAmount();
        //实际提现金额默认与理论提现金额一致
        realAmount = amount;
        //如果 账户余额<(提现金额+实际手续费) 手续费从实际提现金额中扣除
        if (accountBalance.compareTo(amount.add(realFee)) < 0) {
            realAmount = amount.subtract(realFee);
        }

        //如果用户选择加急提现，进行垫资判断，获取应垫资金额
        BigDecimal advanceAmount = null;//应垫资金额
        if (requestDTO.getWithdrawType() != WithdrawTypeEnum.NORMAL) {
            throw new BizException("提现类型应为普通 T1");
        }
        SimpleOrgInfo orgInfo = organizationDubboService.getByOrgId(accountBase.getUserId());
        if( orgInfo == null ){
            throw new BizException("ACC17027");
        }
        //初始化提现订单
        Date createTime = new Date();
        Date expireTime = new DateTime(createTime).plusMinutes(expireMin).toDate();
        WithdrawOrder withdrawOrder = new WithdrawOrder();
        withdrawOrder.setId(snowflakeIdWorker.nextId());
        withdrawOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withdrawOrder.setUserId(accountBase.getUserId());
        withdrawOrder.setAccountId(accountBase.getId());
        withdrawOrder.setAccountRole(accountBase.getAccountRole());
        withdrawOrder.setRealName(orgInfo.getAbbreviation());
        withdrawOrder.setMobileNo(bankCard.getMobileNo());
        withdrawOrder.setBankCardId(bankCard.getId());
        withdrawOrder.setBankCode(bankCard.getBankCode());
        withdrawOrder.setBusinessType(requestDTO.getWithdrawBusinessType().getValue());
        withdrawOrder.setWithdrawType(requestDTO.getWithdrawType().getValue());
        withdrawOrder.setIsAuto(requestDTO.getWithdrawAutoType().getValue());
        withdrawOrder.setAmount(realAmount.add(realFee));
        withdrawOrder.setRealAmout(realAmount);
        withdrawOrder.setFee(fee);
        withdrawOrder.setRealFee(realFee);
        withdrawOrder.setAdvanceAmount(advanceAmount);
        withdrawOrder.setPrizeId(null);
        withdrawOrder.setStatus(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode());
        withdrawOrder.setCreateTime(createTime);
        withdrawOrder.setExpiredTime(expireTime);
        withdrawOrder.setWithdrawFeeRate(withdrawFeeRate);
        withdrawOrder.setFeePaymentUserType(requestDTO.getFeePaymentUserType());
        withdrawOrderService.initWithdrawOrder(withdrawOrder);

        //封装返回对象
        WithdrawOrderDTO withdrawOrderDTO = new WithdrawOrderDTO();
        withdrawOrderDTO.setOrderId(withdrawOrder.getId());
        withdrawOrderDTO.setRequestNo(withdrawOrder.getRequestNo());
        withdrawOrderDTO.setAccountNo(accountBase.getAccountNo());
        withdrawOrderDTO.setExpired(withdrawOrder.getExpiredTime());
        withdrawOrderDTO.setAmount(withdrawOrder.getAmount());
        withdrawOrderDTO.setFee(realFee);
        withdrawOrderDTO.setWithdrawType(WithdrawTypeEnum.enumOf(withdrawOrder.getWithdrawType()));

        return withdrawOrderDTO;
    }

    @Override
    public BigDecimal getFastWithdrawEnableAmountByAccountNo(String accountNo,BigDecimal availableAmount) {
        if(availableAmount == null || BigDecimal.ZERO.compareTo(availableAmount) == 0){
            return BigDecimal.ZERO;
        }
        //查询用户存管账户已到账金额
        QueryUserInformationResponse userAccountInfo = withdrawService.queryAccountInfoRealTime(accountNo);
        BigDecimal userArrivedAmount = userAccountInfo.getArriveBalance();
        //查询垫资账户可用余额
        QueryUserInformationResponse platformAdvanceAccountInfo = withdrawService.queryAccountInfoRealTime(PlateformAccountEnum.SYS_GENERATE_007.name());
        BigDecimal platformAvailableAdvanceAmount = platformAdvanceAccountInfo.getBalance();
        //查询当前系统应垫资金额
        BigDecimal currentNeedAdvanceAmountTotal = withdrawOrderService.queryAdvanceAmountTotal();
        //查询垫资账户保留阈值
        Map<String, String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(Arrays.asList(TradeConfigEnum.WITHDRAWADVANCETHRESHOLD));
        BigDecimal withdrawAdvanceThreshold = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.WITHDRAWADVANCETHRESHOLD.getConfigKey()));
        //计算平台当前可垫资额度
        BigDecimal platformEnableAdvanceAmount = platformAvailableAdvanceAmount.subtract(currentNeedAdvanceAmountTotal).subtract(withdrawAdvanceThreshold);
        if(platformEnableAdvanceAmount.compareTo(BigDecimal.ZERO) < 0 ){
            platformEnableAdvanceAmount = BigDecimal.ZERO;
        }
        //用户可用资金流 = 平台可垫资额度 + 用户自身已到帐金额
        BigDecimal userFastEnableAmount = platformEnableAdvanceAmount.add(userArrivedAmount);
        //用户可用资金流 < 账户余额 ，则实时可到帐金额 = 用户可用资金流
        if(userFastEnableAmount.compareTo(availableAmount) < 0 ){
            return userFastEnableAmount;
        }
        //否则实时可到帐金额为用户余额
        return availableAmount;
    }

    @Override
    public WithdrawOrderResponseDTO queryLastWithdrawSuccessRecord(String userId) {
        WithdrawOrderResponseDTO withdrawOrderResponseDTO=null;
        WithdrawOrder withdrawOrder=withdrawOrderService.queryLastWithdrawSuccessRecord(userId);
        if(withdrawOrder!=null) {
            try {
                withdrawOrderResponseDTO=new WithdrawOrderResponseDTO();
                BeanUtils.copyProperties(withdrawOrderResponseDTO, withdrawOrder);
            } catch (Exception e) {
                log.error("查询最近一笔提现记录,用户ID={},发生系统异常,原因={}", userId, e);
            }
        }
        return withdrawOrderResponseDTO;
    }

    @Override
    public WithdrawOrderResponseDTO getWithdrawOrderById(Long withdrawOrderId) {
        WithdrawOrder withdrawOrder = withdrawOrderService.getWithdrawOrderByIdFromMaster(withdrawOrderId);
        if(withdrawOrder == null){
            return null;
        }
        WithdrawOrderResponseDTO dto = new WithdrawOrderResponseDTO();
        dto.setId(withdrawOrder.getId());
        dto.setAccountRole(withdrawOrder.getAccountRole());
        dto.setAmount(withdrawOrder.getAmount());
        dto.setRealAmount(withdrawOrder.getRealAmout());
        dto.setFee(withdrawOrder.getFee());
        dto.setRealFee(withdrawOrder.getRealFee());
        dto.setStatus(withdrawOrder.getStatus());
        dto.setCreateTime(withdrawOrder.getCreateTime());
        dto.setSuccessTime(withdrawOrder.getSuccessTime());
        if (withdrawOrder.getRemitType() != null) {
            dto.setWithdrawType(withdrawOrder.getRemitType());
        } else {
            dto.setWithdrawType(withdrawOrder.getWithdrawType());
        }
        dto.setBankCardId(withdrawOrder.getBankCardId());
        return dto;
    }

    @Override
    public BigDecimal statSuccessWithdrawAmount(Long accountId) {
        WithdrawOrder queryRequest = new WithdrawOrder();
        queryRequest.setAccountId(accountId);
        queryRequest.setStatus(WithdrawOrderStatusEnum.SUCCESS.getCode());
        List<WithdrawOrder> withdrawOrders = withdrawOrderService.listWithdrawOrders(queryRequest);
        return withdrawOrders.stream().map(WithdrawOrder::getRealAmout).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
    }

    @Override
    public Boolean haveWithdrawingOrder(Long accountId) {
        return withdrawOrderService.queryWithdrawingOrderList(accountId).size()>0;
    }

    @Override
    public BankInfoRespDTO getWithdrawingOrderBankInfo(Long bankCardId) {
        return withdrawOrderService.getWithdrawingOrderBankInfo(bankCardId);
    }

}
